Computer programming languages are used to create applications consisting of human-readable source code that represents instructions for a computer to perform. Before a computer can follow the instructions however, the source code must be translated into computer-readable binary machine code.
A programming language such as C, C++, or COBOL typically uses a compiler to generate assembly language from the source code, and then to translate the assembly language into machine language which is converted to machine code. Thus, the final translation of the source code occurs before runtime. Different computers require different machine languages, so a program written in C++ for example, can only run on the specific hardware platform for which the program was written.
Interpreted programming languages are designed to create applications with source code that will run on multiple hardware platforms. Java™ is an interpreted programming language that accomplishes platform independence by generating source code that is converted before runtime to an intermediate language known as “bytecode” or “virtual machine language.” At runtime, the bytecode is translated into platform-appropriate machine code via interpreter software, as disclosed in U.S. Pat. No. 4,443,865. To interpret each bytecode, interpreter software performs a “fetch, decode, and dispatch” (FDD) series of operations. For each bytecode instruction the interpreter software contains a corresponding execution program expressed in native central processing unit (CPU) instructions. The interpreter software causes the CPU to fetch or read a virtual machine instruction from memory, to decode the CPU address of the execution program for the bytecode instruction, and to dispatch by transferring control of the CPU to that execution program. The interpretation process can be time-consuming.
As disclosed in PCT Patent Application No. WO9918484 adding a preprocessor (a virtual machine interpreter (VMI)) between a memory and a CPU improves the processing of virtual machine instructions. In essence, the virtual machine is not a physical structure, but rather is a self-contained operating environment that interprets bytecode for the hardware platform by selecting the corresponding native machine language instructions that are stored within the VM or in the CPU. The native instructions are then supplied to and consecutively executed in the CPU of the hardware platform. A typical virtual machine requires 20–60 cycles of processing time per bytecode (depending on the quality and complexity of the bytecode) to perform an FDD series of operations.
Further reductions in processing time can be achieved by implementing a hardware accelerator as disclosed in PCT Patent Application Nos. WO9918484 and WO9918486. First, a VMI reads (fetches) a bytecode from memory. Next, the VMI looks up a number of properties of (decodes) the fetched bytecode. One of the properties accessed by the VMI indicates whether the bytecode is simple or complex, which determines whether the VMI can translate the bytecode in hardware. The VMI translates simple Java™ bytecodes into a specialized and optimized sequence of native CPU instructions, which are then fetched and executed by the CPU. While the CPU is executing an instruction, the VMI fetches and translates the next bytecode into CPU instructions. The VMI can process simple bytecodes in 1–4 cycles. If its properties indicate that a bytecode is complex, the VMI generates a generic sequence of native CPU instructions, thereby implementing a “software trap” that directs the complex bytecode to software for interpretation and execution. Upon encountering a complex bytecode, a VMI issues machine code instructions to the CPU that cause the execution of the corresponding native function, i.e. a machine code subroutine residing in the CPU. In response, the CPU interrupts the execution of native instructions generated by the VMI as a result of previous bytecode translations and executes the native function called for by the complex bytecode. The VMI waits to detect renewed fetching from its output buffer and then resumes translation of the sequence of bytecodes. Although it accesses existing native functions rather than translating complex bytecodes instruction by instruction, the VMI reduces the effect of FDD time to almost 0 cycles, because VMI processing of each software trap (5–20 cycles) occurs concurrently with CPU execution of another bytecode.
While interpreting a sequence of bytecodes, a virtual machine may encounter a complex bytecode that is “recursive.” A challenge arises in executing recursive bytecodes (RBCs) because each RBC calls for a native function that eventually results in a method call (i.e., the VMI is reactivated for another sequence of Java bytecodes). Thus, to decode the bytecodes from the other sequence, the native function called for by the RBC must access the values of variables stored in CPU registers. Native functions commonly (but do not always) include standard sets of instructions, hereinafter referred to as “preambles” and “postambles.” The standard preamble is designed to save the content of some or all CPU registers before a subroutine is executed. Some of the content that is saved concerns the values of variables (such as a stack pointer and the return address for reactivating the virtual machine) that may need to be modified during the execution of the native function. However, these variables will not normally be accessible within the native function intended by the RBC because the RBC method call is defined in source code of the programming language, rather than in the machine code that is required to access CPU registers. Furthermore, because the RBC method call cannot access the CPU registers, the standard subroutine postamble cannot write the value of variables that have been modified by the RBC method call back into the CPU registers. In other words, the subroutine called for by a recursive bytecode may not be executed properly because the RBC subroutine cannot access variables stored in CPU registers, either due to a lack of context-setting (no preamble or postambles) or due to an association of incompatible context-setting with the native function called. It is possible to address this challenge by implementing hand-coded software that generates assembly language to write and modify the values of variables for RBC subroutines, however this approach requires a complicated development effort.
There is a need for a system of interpreting programming languages that accurately and efficiently executes instructions intended by recursive bytecodes, while having greater ease of implementation.